package com.micro.school.common.core.utils.file;

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.micro.school.common.core.config.OSSConfig;
import com.micro.school.common.core.utils.DateUtils;
import com.micro.school.common.core.utils.SpringUtils;
import com.micro.school.common.core.utils.StringUtils;
import com.micro.school.common.core.utils.uuid.Seq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Component
public class OssUtil {

    private static final Logger log = LoggerFactory.getLogger(OssUtil.class);

    /**
     * 获取OSS配置
     */
    private static OSSConfig getOSSConfig() {
        return SpringUtils.getBean(OSSConfig.class);
    }

    /**
     * 创建OSS客户端
     * @return OSS实例
     */
    public static OSS createOSSClient() {
        try {
            OSSConfig ossConfig = getOSSConfig();
            if (!ossConfig.isEnabled()) {
                throw new RuntimeException("阿里云OSS未启用，请在配置文件中设置aliyun.oss.enabled=true");
            }

            // 使用配置文件中的Access Key创建凭证提供者
            CredentialsProvider credentialsProvider = new DefaultCredentialProvider(
                    ossConfig.getAccessKeyId(),
                    ossConfig.getAccessKeySecret());
            // 使用DefaultCredentialProvider方法直接设置AK和SK
//            CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());

            //创建ClientConfiguration实例
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);

            // 创建OSS客户端
            return OSSClientBuilder.create()
                    .endpoint(ossConfig.getEndpoint())
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(ossConfig.getRegion())
                    .build();
        } catch (Exception e) {
            log.error("创建OSS客户端失败", e);
            throw new RuntimeException("创建OSS客户端失败", e);
        }
    }

    /**
     * 上传文件到OSS
     *
     * @param inputStream 文件输入流
     * @param objectName 对象名称
     * @return 上传后的URL
     */
    public static String uploadToOSS(InputStream inputStream, String objectName) {
        OSS ossClient = null;
        try {
            OSSConfig ossConfig = getOSSConfig();
            ossClient = createOSSClient();

            // 生成带前缀的对象名
            String fullObjectName = StringUtils.isNotEmpty(ossConfig.getPrefix())
                    ? ossConfig.getPrefix() + "/" + objectName
                    : objectName;

            // 创建PutObjectRequest对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), fullObjectName, inputStream);

            // 上传文件
            PutObjectResult result = ossClient.putObject(putObjectRequest);

            // 返回可访问URL
            return generateAccessUrl(fullObjectName);
        } catch (OSSException oe) {
            log.error("OSS服务端异常: ", oe);
            throw new RuntimeException("OSS服务端异常: " + oe.getMessage(), oe);
        } catch (ClientException ce) {
            log.error("OSS客户端异常: ", ce);
            throw new RuntimeException("OSS客户端异常: " + ce.getMessage(), ce);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 异步上传文件到OSS
     *
     * @param file 文件
     * @param objectName 对象名称
     * @param executor 线程池
     * @return CompletableFuture<String> 异步结果，返回文件的访问URL
     */
    public static CompletableFuture<String> uploadToOSSAsync(MultipartFile file, String objectName, ThreadPoolExecutor executor) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return uploadToOSS(file.getInputStream(), objectName);
            } catch (IOException e) {
                log.error("文件转换为输入流失败", e);
                throw new RuntimeException("文件转换为输入流失败: " + e.getMessage(), e);
            }
        }, executor);
    }

    /**
     * 生成OSS中的文件路径
     *
     * @param file 文件
     * @return 文件路径
     */
    public static String generateOSSObjectName(MultipartFile file) {
        String extension = FileUploadUtils.getExtension(file);
        return StringUtils.format("{}/{}.{}", DateUtils.datePath(), Seq.getId(Seq.uploadSeqType), extension);
    }

    /**
     * 生成文件访问URL
     *
     * @param objectName 对象名称
     * @return 访问URL
     */
    private static String generateAccessUrl(String objectName) {
        OSSConfig ossConfig = getOSSConfig();

        // 如果配置了自定义域名，则使用自定义域名
        if (StringUtils.isNotEmpty(ossConfig.getDomain())) {
            return StringUtils.format("{}/{}", ossConfig.getDomain(), objectName);
        }

        // 否则使用默认的bucket访问域名
        return StringUtils.format("https://{}.{}/{}",
                ossConfig.getBucketName(),
                ossConfig.getEndpoint().replace("https://", ""),
                objectName);
    }
}